"""战斗引擎"""

import json
from typing import List, Dict, Any, Optional
from models.battle import Battle, BattleStatus, BattleResult, BattleAction
from models.character import Character, CharacterType
from models.battlefield import Battlefield
from models.skill import Skill, SkillLibrary
from models.skill_template import SkillTemplateLibrary


class BattleEngine:
    """战斗引擎类"""
    
    def __init__(self):
        self.current_battle: Optional[Battle] = None
        self.skill_library = {}  # 动态技能库，按需加载
    
    def create_battle(self, battle_id: str) -> Battle:
        """创建新战斗"""
        battlefield = Battlefield()
        battle = Battle(battle_id=battle_id, battlefield=battlefield)
        self.current_battle = battle
        return battle
    
    def setup_characters(self, player_setup: List[Dict], enemy_setup: List[Dict]) -> bool:
        """设置战斗角色
        
        Args:
            player_setup: 玩家方角色设置 [{"character": Character, "x": int, "y": int}, ...]
            enemy_setup: 敌方角色设置 [{"character": Character, "x": int, "y": int}, ...]
        """
        if not self.current_battle:
            return False
        
        # 添加玩家方角色
        for setup in player_setup:
            character = setup["character"]
            x, y = setup["x"], setup["y"]
            if not self.current_battle.add_character(character, x, y):
                return False
        
        # 添加敌方角色
        for setup in enemy_setup:
            character = setup["character"]
            x, y = setup["x"], setup["y"]
            if not self.current_battle.add_character(character, x, y):
                return False
        
        return True
    
    def start_battle(self) -> bool:
        """开始战斗"""
        if not self.current_battle:
            return False
        
        # 检查是否有足够的角色
        if not self.current_battle.player_characters or not self.current_battle.enemy_characters:
            return False
        
        self.current_battle.start_battle()
        return True
    
    def execute_turn(self, character_id: str, skill_id: str, target_x: int, target_y: int) -> Dict[str, Any]:
        """执行一个回合的行动"""
        if not self.current_battle or self.current_battle.status != BattleStatus.ONGOING:
            return {"success": False, "error": "战斗未在进行中"}
        
        try:
            # 获取技能
            skill = self._get_skill(skill_id)
            if not skill:
                return {"success": False, "error": f"技能 {skill_id} 不存在"}
            
            # 如果是新回合，创建回合对象
            if not self.current_battle.rounds or len(self.current_battle.rounds[-1].actions) == 0:
                current_round = self.current_battle.next_round()
            else:
                current_round = self.current_battle.rounds[-1]
            
            # 执行行动
            action = self.current_battle.execute_action(character_id, skill, target_x, target_y)
            current_round.actions.append(action)
            
            # 检查战斗是否结束
            winner = self.current_battle.check_battle_end()
            if winner:
                result = self.current_battle.end_battle(winner)
                return {
                    "success": True,
                    "action": self._action_to_dict(action),
                    "battle_ended": True,
                    "winner": winner.value,
                    "battle_result": result.to_dict()
                }
            
            return {
                "success": True,
                "action": self._action_to_dict(action),
                "battle_ended": False
            }
            
        except Exception as e:
            return {"success": False, "error": str(e)}
    
    def auto_battle_round(self) -> Dict[str, Any]:
        """自动执行一个完整回合（所有角色按速度顺序行动）"""
        if not self.current_battle or self.current_battle.status != BattleStatus.ONGOING:
            return {"success": False, "error": "战斗未在进行中"}
        
        try:
            # 创建新回合
            current_round = self.current_battle.next_round()
            
            # 获取行动顺序
            turn_order = self.current_battle.get_turn_order()
            
            round_actions = []
            
            for character in turn_order:
                if not character.is_alive:
                    continue
                
                # AI选择行动
                action_result = self._ai_choose_action(character)
                if action_result:
                    skill_id, target_x, target_y = action_result
                    skill = self._get_skill(skill_id)
                    if not skill:
                        continue
                    
                    # 检查技能是否可用
                    if character.is_skill_available(skill_id):
                        try:
                            # 验证目标位置和攻击范围
                            if (self.current_battle.battlefield.is_valid_position(target_x, target_y) and 
                                skill.can_target_position(character.position_x, character.position_y, target_x, target_y)):
                                
                                # 使用技能并设置冷却
                                character.use_skill(skill_id, skill.cooldown)
                                
                                action = self.current_battle.execute_action(character.id, skill, target_x, target_y)
                                current_round.actions.append(action)
                                round_actions.append(self._action_to_dict(action))
                                
                                # 检查战斗是否结束
                                winner = self.current_battle.check_battle_end()
                                if winner:
                                    result = self.current_battle.end_battle(winner)
                                    return {
                                        "success": True,
                                        "round_number": current_round.round_number,
                                        "actions": round_actions,
                                        "battle_ended": True,
                                        "winner": winner.value,
                                        "battle_result": result.to_dict()
                                    }
                            else:
                                # 目标位置无效或超出攻击范围，跳过这个角色的行动
                                print(f"警告: 角色 {character.name} 选择的目标位置 ({target_x}, {target_y}) 无效或超出攻击范围，跳过行动")
                        except Exception as e:
                            # 单个角色行动失败不应该终止整个回合
                            print(f"警告: 角色 {character.name} 行动失败: {e}，跳过行动")
                    else:
                        pass
                else:
                    pass
            
            # 回合结束处理
            all_characters = self.current_battle.get_all_characters()
            
            # 1. 减少所有角色的技能冷却时间
            for character in all_characters:
                character.reduce_cooldowns()
            
            # 2. 处理被动技能效果（如再生、荆棘反击等）
            passive_effects = self._process_passive_skills(all_characters)
            
            # 3. 统计回合结束时的角色状态
            round_end_stats = self._get_round_end_stats(all_characters)
            
            return {
                "success": True,
                "round_number": current_round.round_number,
                "actions": round_actions,
                "passive_effects": passive_effects,
                "round_end_stats": round_end_stats,
                "battle_ended": False
            }
            
        except Exception as e:
            return {"success": False, "error": str(e)}
    
    def _ai_choose_action(self, character: Character) -> Optional[tuple]:
        """AI选择行动（智能AI逻辑）"""
        if character.position_x is None or character.position_y is None:
            return None
        
        # 获取敌方角色和友方角色
        if character.character_type == CharacterType.PLAYER:
            enemies = self.current_battle.get_alive_characters(CharacterType.ENEMY)
            allies = self.current_battle.get_alive_characters(CharacterType.PLAYER)
        else:
            enemies = self.current_battle.get_alive_characters(CharacterType.PLAYER)
            allies = self.current_battle.get_alive_characters(CharacterType.ENEMY)
        
        # 获取当前可用的技能（只检查角色实际拥有的技能）
        available_skills = {}
        # 使用角色实际拥有的技能
        for skill_id in character.skills:
            skill = self._get_skill(skill_id)
            if skill and character.is_skill_available(skill_id):
                available_skills[skill_id] = skill
        
        # AI策略优先级：
        # 1. 如果有友军生命值低于30%，优先使用治疗技能
        # 2. 如果有多个敌人聚集，优先使用范围攻击技能
        # 3. 使用各种单体攻击技能
        # 4. 使用增益技能
        
        # 检查是否需要紧急治疗
        critical_allies = [ally for ally in allies if ally.current_hp < ally.max_hp * 0.3 and ally.position_x is not None]
        if critical_allies:
            # 寻找治疗技能
            heal_skills = [skill_id for skill_id, skill in available_skills.items() 
                          if skill.skill_type.value == "heal"]
            
            for heal_skill_id in heal_skills:
                skill = available_skills[heal_skill_id]
                if skill.target_type.value == "area":  # 群体治疗
                    best_target = self._find_best_heal_target(critical_allies, allies, skill)
                    if best_target:
                        return (heal_skill_id, best_target[0], best_target[1])
                elif skill.target_type.value == "single" and critical_allies:  # 单体治疗
                    target = critical_allies[0]
                    return (heal_skill_id, target.position_x, target.position_y)
        
        # 检查是否有友军生命值低于60%需要治疗
        injured_allies = [ally for ally in allies if ally.current_hp < ally.max_hp * 0.6 and ally.position_x is not None]
        if injured_allies and len(injured_allies) >= 2:
            heal_skills = [skill_id for skill_id, skill in available_skills.items() 
                          if skill.skill_type.value == "heal" and skill.target_type.value == "area"]
            for heal_skill_id in heal_skills:
                skill = available_skills[heal_skill_id]
                best_target = self._find_best_heal_target(injured_allies, allies, skill)
                if best_target:
                    return (heal_skill_id, best_target[0], best_target[1])
        
        # 攻击敌人
        if enemies:
            # 优先使用范围攻击技能攻击聚集的敌人
            area_damage_skills = [skill_id for skill_id, skill in available_skills.items() 
                                 if skill.skill_type.value == "damage" and skill.target_type.value == "area"]
            
            for skill_id in area_damage_skills:
                skill = available_skills[skill_id]
                best_target = self._find_best_area_attack_target(enemies, skill)
                if best_target:
                    return (skill_id, best_target[0], best_target[1])
            
            # 使用单体攻击技能攻击敌人
            single_damage_skills = [skill_id for skill_id, skill in available_skills.items() 
                                   if skill.skill_type.value == "damage" and skill.target_type.value == "single"]
            
            if single_damage_skills and enemies:
                # 选择伤害最高的技能
                best_skill_id = max(single_damage_skills, 
                                   key=lambda s: available_skills[s].base_value + available_skills[s].percentage_value)
                
                valid_enemies = [e for e in enemies if e.position_x is not None and e.position_y is not None and e.is_alive]
                if valid_enemies:
                    skill = available_skills[best_skill_id]
                    # 找到在攻击范围内生命值最低的敌人
                    for target_enemy in sorted(valid_enemies, key=lambda e: e.current_hp):
                        if skill.can_target_position(character.position_x, character.position_y, 
                                                   target_enemy.position_x, target_enemy.position_y):
                            return (best_skill_id, target_enemy.position_x, target_enemy.position_y)
        
        # 如果没有其他选择，使用基础攻击
        if "basic_attack" in available_skills and enemies:
            valid_enemies = [e for e in enemies if e.position_x is not None and e.position_y is not None and e.is_alive]
            if valid_enemies:
                skill = available_skills["basic_attack"]
                # 找到在攻击范围内最近的敌人
                for closest_enemy in sorted(valid_enemies, key=lambda e: 
                    abs(e.position_x - character.position_x) + abs(e.position_y - character.position_y)):
                    if skill.can_target_position(character.position_x, character.position_y, 
                                               closest_enemy.position_x, closest_enemy.position_y):
                        return ("basic_attack", closest_enemy.position_x, closest_enemy.position_y)
        
        return None
    
    def _find_best_heal_target(self, priority_allies: List[Character], all_allies: List[Character], heal_skill) -> Optional[tuple]:
        """找到最佳治疗目标位置"""
        best_target = None
        max_heal_count = 0
        
        for ally in priority_allies:
            if ally.position_x is None or ally.position_y is None or not ally.is_alive:
                continue
            
            # 计算在这个位置使用治疗技能能治疗多少友军
            targets = heal_skill.get_targets(None, ally.position_x, ally.position_y, self.current_battle.battlefield, all_allies)
            heal_count = len([t for t in targets if t.current_hp < t.max_hp])
            
            if heal_count > max_heal_count:
                max_heal_count = heal_count
                best_target = (ally.position_x, ally.position_y)
        
        return best_target if max_heal_count > 0 else None
    
    def _find_best_area_attack_target(self, enemies: List[Character], area_skill) -> Optional[tuple]:
        """找到最佳范围攻击目标位置"""
        best_target = None
        max_damage_targets = 0
        
        for enemy in enemies:
            if enemy.position_x is None or enemy.position_y is None or not enemy.is_alive:
                continue
            
            # 计算在这个位置使用范围技能能攻击多少敌人
            targets = area_skill.get_targets(None, enemy.position_x, enemy.position_y, self.current_battle.battlefield, enemies)
            target_count = len(targets)
            
            if target_count > max_damage_targets:
                max_damage_targets = target_count
                best_target = (enemy.position_x, enemy.position_y)
        
        # 只有能攻击到2个或以上敌人时才使用范围攻击
        return best_target if max_damage_targets >= 2 else None
    
    def _action_to_dict(self, action: BattleAction) -> Dict[str, Any]:
        """将行动转换为字典"""
        return {
            "character_id": action.character_id,
            "skill_id": action.skill_id,
            "target": {"x": action.target_x, "y": action.target_y},
            "effects": [
                {
                    "target_id": effect.target_id,
                    "effect_type": effect.effect_type,
                    "value": effect.effect_value,
                    "is_hit": effect.is_hit,
                    "is_crit": effect.is_crit,
                    "is_dodged": effect.is_dodged
                } for effect in action.effects
            ],
            "timestamp": action.timestamp
        }
    
    def get_battle_state(self) -> Optional[Dict[str, Any]]:
        """获取当前战斗状态"""
        if not self.current_battle:
            return None
        
        return {
            "battle_id": self.current_battle.battle_id,
            "status": self.current_battle.status.value,
            "current_round": self.current_battle.current_round,
            "player_characters": [char.to_dict() for char in self.current_battle.player_characters],
            "enemy_characters": [char.to_dict() for char in self.current_battle.enemy_characters],
            "battlefield": self.current_battle.battlefield.to_dict()
        }
    
    def _get_skill(self, skill_id: str) -> Optional[Skill]:
        """动态获取技能，优先从缓存获取，否则从模板创建"""
        # 先检查缓存
        if skill_id in self.skill_library:
            return self.skill_library[skill_id]
        
        # 尝试从技能模板创建
        try:
            skill = SkillTemplateLibrary.create_skill_from_template(skill_id, skill_id)
            self.skill_library[skill_id] = skill  # 缓存技能
            return skill
        except ValueError:
            # 如果模板不存在，尝试从旧的SkillLibrary获取
            try:
                skill = SkillLibrary.create_skill_from_id(skill_id)
                self.skill_library[skill_id] = skill  # 缓存技能
                return skill
            except ValueError:
                return None
    
    def get_available_skills(self) -> Dict[str, Dict[str, Any]]:
        """获取可用技能列表"""
        return {skill_id: skill.to_dict() for skill_id, skill in self.skill_library.items()}
    
    def _process_passive_skills(self, characters: List[Character]) -> List[Dict[str, Any]]:
        """处理被动技能效果"""
        passive_effects = []
        
        for character in characters:
            if not character.is_alive:
                continue
                
            # 检查角色的被动技能
            for skill_id in character.skills:
                skill = self._get_skill(skill_id)
                if not skill:
                    continue
                    
                # 处理再生类被动技能
                if "regeneration" in skill_id.lower() or "再生" in skill.name:
                    if character.current_hp < character.max_hp:
                        # 每回合恢复最大生命值的5%
                        heal_amount = max(1, int(character.max_hp * 0.05))
                        actual_heal = character.heal(heal_amount)
                        if actual_heal > 0:
                            passive_effects.append({
                                "character_id": character.id,
                                "skill_name": skill.name,
                                "effect_type": "heal",
                                "value": actual_heal,
                                "description": f"{character.name} 通过 {skill.name} 恢复了 {actual_heal} 点生命值"
                            })
                
                # 处理钢铁皮肤类被动技能（临时防御提升）
                elif "steel_skin" in skill_id.lower() or "钢铁皮肤" in skill.name:
                    # 这里可以添加防御提升逻辑
                    pass
                    
                # 处理战斗狂热类被动技能（临时攻击提升）
                elif "battle_frenzy" in skill_id.lower() or "战斗狂热" in skill.name:
                    # 这里可以添加攻击提升逻辑
                    pass
        
        return passive_effects
    
    def _get_round_end_stats(self, characters: List[Character]) -> Dict[str, Any]:
        """获取回合结束时的角色状态统计"""
        player_stats = []
        enemy_stats = []
        
        for character in characters:
            char_stat = {
                "id": character.id,
                "name": character.name,
                "current_hp": character.current_hp,
                "max_hp": character.max_hp,
                "hp_percentage": round((character.current_hp / character.max_hp) * 100, 1) if character.max_hp > 0 else 0,
                "position": {
                    "x": character.position_x,
                    "y": character.position_y
                },
                "is_alive": character.is_alive,
                "status_effects": [],  # 预留状态效果字段
                "skill_cooldowns": dict(character.skill_cooldowns)
            }
            
            if character.character_type == CharacterType.PLAYER:
                player_stats.append(char_stat)
            else:
                enemy_stats.append(char_stat)
        
        return {
            "player_team": {
                "alive_count": len([c for c in player_stats if c["is_alive"]]),
                "total_count": len(player_stats),
                "characters": player_stats
            },
            "enemy_team": {
                "alive_count": len([c for c in enemy_stats if c["is_alive"]]),
                "total_count": len(enemy_stats),
                "characters": enemy_stats
            }
        }